#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
集成优化器 - 结合遗传算法和启发式算法
Integrated Optimizer: Combining Genetic Algorithm and Heuristic Methods
"""

import pandas as pd
import numpy as np
import random
from typing import List, Tuple, Dict
import json

class IntegratedPBSOptimizer:
    """集成优化器"""
    
    def __init__(self):
        self.cars = []
        self.color_map = {}
        self.drive_map = {}
        self.n_cars = 0
        
    def load_data(self):
        """加载数据"""
        df = pd.read_excel('附件1.xlsx')
        df.columns = ['sequence', 'config', 'color', 'drive']
        
        self.cars = []
        for _, row in df.iterrows():
            car = {
                'id': int(row['sequence']),
                'config': str(row['config']),
                'color': str(row['color']),
                'drive': str(row['drive'])
            }
            self.cars.append(car)
            
            self.color_map[car['id']] = car['color']
            self.drive_map[car['id']] = car['drive']
        
        self.n_cars = len(self.cars)
        print(f"加载 {self.n_cars} 辆车")
        print(f"颜色分布: {dict(df['color'].value_counts())}")
        print(f"驱动分布: {dict(df['drive'].value_counts())}")
    
    def calculate_objectives(self, sequence: List[int]) -> Dict[str, float]:
        """计算所有目标得分"""
        # 颜色切换
        colors = [self.color_map[id] for id in sequence]
        color_switches = sum(1 for i in range(1, len(colors)) if colors[i] != colors[i-1])
        color_score = max(0, 100 - (color_switches / (len(sequence)-1)) * 100)
        
        # 驱动比例平衡
        drives = [self.drive_map[id] for id in sequence]
        drive_deviation = 0
        for i in range(0, len(drives), 4):
            window = drives[i:i+4]
            if len(window) >= 2:
                two = window.count('两驱')
                four = window.count('四驱')
                deviation = abs(two - len(window)/2) + abs(four - len(window)/2)
                drive_deviation += deviation
        drive_score = max(0, 100 - (drive_deviation / max(1, len(sequence))) * 100)
        
        # PBS利用率
        schedule = self.create_schedule_matrix(sequence)
        used = np.sum(schedule > 0)
        total = schedule.shape[0] * schedule.shape[1]
        utilization = used / total
        util_score = utilization * 100
        
        # 时间得分
        max_col_time = 0
        for col in range(schedule.shape[1]):
            col_cars = schedule[:, col]
            col_cars = col_cars[col_cars > 0]
            if len(col_cars) > 0:
                col_time = len(col_cars) * 9 + 12
                max_col_time = max(max_col_time, col_time)
        
        min_time = 9 * len(sequence) + 72
        time_penalty = max(0, max_col_time - min_time) * 0.1
        time_score = max(0, 100 - time_penalty)
        
        # 加权总分
        total_score = (color_score * 0.4 + drive_score * 0.3 + 
                      util_score * 0.2 + time_score * 0.1)
        
        return {
            'color_switching': color_score,
            'drive_ratio': drive_score,
            'pbs_utilization': util_score,
            'total_time': time_score,
            'total_score': total_score,
            'color_switches': color_switches,
            'drive_deviation': drive_deviation
        }
    
    def create_schedule_matrix(self, sequence: List[int]) -> np.ndarray:
        """创建调度矩阵"""
        n_cols = max(100, (len(sequence) + 9) // 10)
        schedule = np.zeros((10, n_cols), dtype=int)
        
        car_idx = 0
        for col in range(n_cols):
            for row in range(10):
                if car_idx < len(sequence):
                    schedule[row, col] = sequence[car_idx]
                    car_idx += 1
                else:
                    break
            if car_idx >= len(sequence):
                break
        
        return schedule
    
    def heuristic_color_first(self) -> List[int]:
        """颜色优先启发式"""
        electric = [car['id'] for car in self.cars if car['color'] == '电动']
        combustion = [car['id'] for car in self.cars if car['color'] == '燃动']
        return electric + combustion
    
    def heuristic_drive_balanced(self) -> List[int]:
        """驱动平衡启发式"""
        two = [car['id'] for car in self.cars if car['drive'] == '两驱']
        four = [car['id'] for car in self.cars if car['drive'] == '四驱']
        
        # 交错排列
        sequence = []
        i, j = 0, 0
        while i < len(two) or j < len(four):
            if i < len(two):
                sequence.append(two[i])
                i += 1
            if j < len(four):
                sequence.append(four[j])
                j += 1
        return sequence
    
    def genetic_algorithm(self, generations=50, pop_size=50) -> List[int]:
        """遗传算法"""
        print("=== 遗传算法优化 ===")
        
        # 初始化种群
        base = [car['id'] for car in self.cars]
        population = []
        
        # 启发式初始解
        strategies = [
            base.copy(),
            self.heuristic_color_first(),
            self.heuristic_drive_balanced(),
        ]
        
        for seq in strategies:
            fitness = self.calculate_objectives(seq)['total_score']
            population.append((seq, fitness))
        
        # 填充随机
        for _ in range(pop_size - len(strategies)):
            seq = base.copy()
            random.shuffle(seq)
            fitness = self.calculate_objectives(seq)['total_score']
            population.append((seq, fitness))
        
        # 进化
        for gen in range(generations):
            population.sort(key=lambda x: x[1], reverse=True)
            
            if gen % 10 == 0:
                print(f"第{gen}代: 最佳={population[0][1]:.2f}")
            
            # 选择前50%作为亲本
            parents = population[:pop_size//2]
            new_population = parents.copy()
            
            # 生成后代
            while len(new_population) < pop_size:
                p1, p2 = random.sample(parents, 2)
                
                # 交叉
                child = self.crossover(p1[0], p2[0])
                
                # 变异
                if random.random() < 0.1:
                    child = self.mutate(child)
                
                fitness = self.calculate_objectives(child)['total_score']
                new_population.append((child, fitness))
            
            population = new_population[:pop_size]
        
        return population[0][0]
    
    def crossover(self, parent1: List[int], parent2: List[int]) -> List[int]:
        """顺序交叉"""
        n = len(parent1)
        start, end = sorted(random.sample(range(n), 2))
        
        child = [0] * n
        child[start:end+1] = parent1[start:end+1]
        
        ptr = (end + 1) % n
        for gene in parent2:
            if gene not in child:
                child[ptr] = gene
                ptr = (ptr + 1) % n
        
        return child
    
    def mutate(self, sequence: List[int]) -> List[int]:
        """交换变异"""
        i, j = random.sample(range(len(sequence)), 2)
        sequence[i], sequence[j] = sequence[j], sequence[i]
        return sequence
    
    def compare_all_methods(self) -> Dict[str, Dict]:
        """比较所有优化方法"""
        methods = {
            '原始顺序': [car['id'] for car in self.cars],
            '颜色优先': self.heuristic_color_first(),
            '驱动平衡': self.heuristic_drive_balanced(),
            '遗传算法': self.genetic_algorithm(generations=30, pop_size=30)
        }
        
        results = {}
        for name, sequence in methods.items():
            scores = self.calculate_objectives(sequence)
            results[name] = scores
            print(f"\n{name}:")
            print(f"  总得分: {scores['total_score']:.2f}")
            print(f"  颜色切换: {scores['color_switches']}次")
            print(f"  驱动偏差: {scores['drive_deviation']:.1f}")
        
        return results
    
    def generate_final_results(self, best_sequence: List[int], method_name: str):
        """生成最终结果文件"""
        # 创建调度矩阵
        schedule = self.create_schedule_matrix(best_sequence)
        
        # 保存调度矩阵
        pd.DataFrame(schedule).to_excel('result11.xlsx', index=False, header=False)
        
        # 保存车辆序列
        sequence_data = []
        for car_id in best_sequence:
            car = next(c for c in self.cars if c['id'] == car_id)
            sequence_data.append(car)
        
        pd.DataFrame(sequence_data).to_excel('result12.xlsx', index=False)
        
        # 保存详细结果
        scores = self.calculate_objectives(best_sequence)
        result_summary = {
            '优化方法': method_name,
            '总得分': scores['total_score'],
            '颜色切换得分': scores['color_switching'],
            '驱动比例得分': scores['drive_ratio'],
            '缓存区利用率得分': scores['pbs_utilization'],
            '总时间得分': scores['total_time'],
            '颜色切换次数': scores['color_switches'],
            '驱动偏差值': scores['drive_deviation']
        }
        
        pd.DataFrame([result_summary]).to_excel('optimization_summary.xlsx', index=False)
        
        print(f"\n=== 最终结果已生成 ===")
        print(f"优化方法: {method_name}")
        print(f"总得分: {scores['total_score']:.2f}")
        print(f"文件: result11.xlsx, result12.xlsx, optimization_summary.xlsx")

def main():
    """主函数"""
    optimizer = IntegratedPBSOptimizer()
    optimizer.load_data()
    
    # 比较所有方法
    results = optimizer.compare_all_methods()
    
    # 选择最佳方案
    best_method = max(results.keys(), key=lambda x: results[x]['total_score'])
    best_sequence = None
    
    if best_method == '原始顺序':
        best_sequence = [car['id'] for car in optimizer.cars]
    elif best_method == '颜色优先':
        best_sequence = optimizer.heuristic_color_first()
    elif best_method == '驱动平衡':
        best_sequence = optimizer.heuristic_drive_balanced()
    elif best_method == '遗传算法':
        best_sequence = optimizer.genetic_algorithm()
    
    # 生成最终文件
    optimizer.generate_final_results(best_sequence, best_method)
    
    return results

if __name__ == "__main__":
    results = main()